package cmd

import (
	"context"
	"fmt"
	"os"
	"strings"
	"sync"
	"time"

	"gitee.com/wx-rdc/secloud-demo/util"
	sdk "gitee.com/wx-rdc/secloud-sdk-go/secloud"
	"github.com/antihax/optional"
	"github.com/spf13/cobra"
)

var benchCmd = &cobra.Command{
	Use:   "bench",
	Short: "mytool bench operations",
	Long:  `mytool bench: bench test`,
	Run: func(cmd *cobra.Command, args []string) {
		runBench()
	},
}

func initBench() {
	// benchCmd.Flags().StringVarP(&nameDesc, "desc", "D", "", "description of this person")
	rootCmd.AddCommand(benchCmd)
}

func runBench() {
	// create api client
	client := sdk.NewAPIClient(sdk.NewConfiguration(API_URL))

	// auth api
	authOpts := &sdk.AuthOpts{
		ClientId:     optional.NewString(CLIENT_ID),
		ClientSecret: optional.NewString(CLIENT_SECRET),
	}
	data, err := client.AuthApi.Token(context.Background(), authOpts)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	accessCtx := context.WithValue(
		context.Background(),
		sdk.ContextAccessToken, data.AccessToken)

	// encrypt
	encryptOpts := &sdk.EncryptOpts{
		KeyId: optional.NewString(WORKING_KEY_ID),
		Data:  optional.NewString("abcdefghijklmnopqrstuvwxyz"),
	}
	// // decrypt
	decryptOpts := &sdk.DecryptOpts{
		EncData: optional.NewString("eyJkIjoiRW1ZUTJvMm9SKzNudzNnck1RbnNqV1IxTjdmSFBSRUszd1g0NHVoRkxzUVx1MDAzZCIsImkiOiJoNFhGZDJQWXBZaHZJRGs2IiwiayI6IjBzK1p4OXgyMXRKTU1zNDlBaENabVFcdTAwM2RcdTAwM2QifQ=="),
	}

	loopCount := 5000
	encErr := 0
	decErr := 0
	recoverErr := 0
	// 限制最大并发数为100
	limitGoroutine := make(chan int, 500)
	var wg sync.WaitGroup
	start := time.Now()
	wg.Add(loopCount)
	for i := 0; i < loopCount; i++ {
		// 每启动一个协程，就往channel里写入一位数
		limitGoroutine <- 0
		localCount := i
		go func() {
			// 使用defer, 表示函数完成时将等待组值减1
			defer func() {
				wg.Done()
				<-limitGoroutine
				// 发生宕机时，获取panic传递的上下文并打印
				if err := recover(); err != nil {
					recoverErr += 1
				}
			}()

			fmt.Printf("\rloop: %s", util.Cyan(fmt.Sprintf("%d", localCount+1)))
			// fmt.Printf("[%d] running", localCount)
			encryptResp, err := client.CipherApi.Encrypt(accessCtx, encryptOpts)
			if err != nil || len(encryptResp.EncData) < 100 {
				encErr += 1
				return
				// fmt.Printf("[%d] encdata: %s\n", localCount, encryptResp.EncData)
				// os.Exit(1)
			}
			// fmt.Printf("Encrypt data: %s\n", encryptResp.EncData)

			// decrypt
			// decryptOpts := &sdk.DecryptOpts{
			// 	EncData: optional.NewString(encryptResp.EncData),
			// }
			decryptResp, err := client.CipherApi.Decrypt(accessCtx, decryptOpts)
			if err != nil || !strings.EqualFold(decryptResp.Data, encryptOpts.Data.Value()) {
				decErr += 1
				// fmt.Printf("%s - %s, not equal\n", decryptResp.Data, encryptOpts.Data.Value())
				// fmt.Printf("[%d] encdata: %s\n", localCount, decryptOpts.EncData.Value())
				// os.Exit(1)
			}
		}()
	}
	// 等待所有的任务完成
	wg.Wait()

	// fmt.Printf("Decrypt data: %s\n", decryptResp.Data)
	cost := time.Since(start)
	fmt.Println("\rcost:", cost)
	fmt.Printf("encErr: %d\tdecErr: %d\trecoverErr: %d\n", encErr, decErr, recoverErr)
}
